package com.ttg.web.service.job.impl;

import com.google.common.util.concurrent.ListenableFuture;
import com.ttg.common.annotation.TaskRunMethod;
import com.ttg.common.dto.TaskBaseDTO;
import com.ttg.common.enums.CreditFlagEnum;
import com.ttg.common.enums.UseCreditFlagEnum;
import com.ttg.common.exception.BaseException;
import com.ttg.common.utils.BigDecimalUtils;
import com.ttg.common.utils.LongUtil;
import com.ttg.common.vo.TaskResultVO;
import com.ttg.model.po.AccountInfoPO;
import com.ttg.model.vo.MerchTradeInfoByMonthVO;
import com.ttg.model.pojo.CostManageMerchDepositLoan;
import com.ttg.model.pojo.QualityManageMerchReport;
import com.ttg.web.dao.CostManageMerchDepositLoanDao;
import com.ttg.web.dao.QualityManageMerchReportDao;
import com.ttg.web.juc.TasktemplateHelper;
import com.ttg.web.service.job.JobCommon;
import com.ttg.web.service.job.MerchDepositJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description： 商户存贷信息任务
 * Author: chenyou
 * Date: 2025/9/15 15:50
 * Company: ttg
 * Copyright: Copyright (c) 2025
 */
@Slf4j
@Service
@TaskRunMethod(value = "merchDepositTask")
public class MerchDepositJobServiceImpl extends JobCommon implements MerchDepositJobService {

    @Value("${tlinx.isJuc:false}")
    private volatile Boolean isJuc;//是否启用异步回调
    @Autowired
    private TasktemplateHelper tasktemplateHelper;
    @Autowired
    private CostManageMerchDepositLoanDao merchDepositLoanDao;
    @Autowired
    private QualityManageMerchReportDao merchReportDao;

    @Override
    public TaskResultVO merchDeposit(TaskBaseDTO reqDto) {
        reqDto = getCheckYearAndMonth(reqDto);
        //todo 商户信息
        List<MerchTradeInfoByMonthVO> mctList = getMerchList();

        List<ListenableFuture<TaskResultVO>> futures = new ArrayList<>();
        List<TaskResultVO> results = new ArrayList<>();

        for(MerchTradeInfoByMonthVO mct : mctList){
            if(isJuc){
                futures.add(tasktemplateHelper.submit(this,reqDto,mct));
            }else {
                TaskResultVO result = merchDepositTask(reqDto,mct);
                results.add(result);
            }
        }
        return taskResult(results,futures,isJuc);
    }

    public TaskResultVO merchDepositTask(TaskBaseDTO reqDto, MerchTradeInfoByMonthVO merchTradeInfoByMonthVO){
        try {
            //todo 指定二级行业直绑账户数据
            List<AccountInfoPO> bindAcctList = getBindAcctList();
            //todo 指定二级行业全量账户数据
            List<AccountInfoPO> allAcctList = getAllAcctList();

            //1. 商户基础信息
            CostManageMerchDepositLoan merchDepositLoan = new CostManageMerchDepositLoan();
            merchDepositLoan.setCmmdIntervalType(reqDto.getIntervalType());
            merchDepositLoan.setCmmdYear(reqDto.getYear());
            merchDepositLoan.setCmmdMonth(reqDto.getMonth());
            merchDepositLoan.setCmmdClsId1(merchTradeInfoByMonthVO.getClsId1());
            merchDepositLoan.setCmmdClsId2(merchTradeInfoByMonthVO.getClsId2());
            merchDepositLoan.setCmmdMctNo(merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdMctName(merchTradeInfoByMonthVO.getMctName());
            merchDepositLoan.setCmmdCustNo(merchTradeInfoByMonthVO.getMctCustNo());
            //2. 存款情况
            //2.1 直绑账户-月日均规模
            Long bindMonthAvgAmt = monthAvgAmtSum(bindAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdBindMonthAvgAmt(new BigDecimal(bindMonthAvgAmt));
            //2.2 直绑账户-月末时点规模
            Long bindMonthLastdayAmt = monthLastdayAmtSum(bindAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdBindMonthLastdayAmt(new BigDecimal(bindMonthLastdayAmt));
            //2.3 直绑账户-偏离度
            BigDecimal bindDeviationDegree = deviationDegree(bindMonthAvgAmt, bindMonthLastdayAmt);
            merchDepositLoan.setCmmdBindDeviationDegree(bindDeviationDegree);
            //2.4 直绑账户-加权利率
            BigDecimal bindWeightRate = weightDepositRate(bindAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdBindWeightRate(bindWeightRate);

            //2.5 全量账户-月日均规模
            Long monthAvgAmt = monthAvgAmtSum(allAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdMonthAvgAmt(new BigDecimal(monthAvgAmt));
            //2.6 全量账户-月末时点规模
            Long monthLastdayAmt = monthLastdayAmtSum(allAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdMonthLastdayAmt(new BigDecimal(monthLastdayAmt));
            //2.7 全量账户-偏离度
            BigDecimal deviationDegree = deviationDegree(monthAvgAmt, monthLastdayAmt);
            merchDepositLoan.setCmmdDeviationDegree(deviationDegree);
            //2.8 全量账户-加权利率
            BigDecimal weightRate = weightDepositRate(allAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdWeightRate(weightRate);

            //3. 贷款情况
            //3.1 授信规模
            BigDecimal creditTotalAmt = creditAmtSum(allAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdCreditAmt(creditTotalAmt);
            //3.1 用信规模
            BigDecimal useCreditTotalAmt = useCreditAmtSum(allAcctList, merchTradeInfoByMonthVO.getMctNo());
            merchDepositLoan.setCmmdUseCreditAmt(useCreditTotalAmt);
            //3.1 存贷比
            BigDecimal ratio = ratio(useCreditTotalAmt, bindMonthAvgAmt);
            merchDepositLoan.setCmmdRatio(ratio);
            //4. 指导分类
            QualityManageMerchReport merchReport = merchReportDao.getByUnique(reqDto.getYear(),reqDto.getMonth(), merchTradeInfoByMonthVO.getMctNo().toString());
            if (merchReport == null) {
                throw new BaseException(reqDto.getYear()+reqDto.getMonth() + ",缺少商户质量报告记录");
            }
            if(merchReport.getRepQtrId()==null){
                throw new BaseException(reqDto.getYear()+reqDto.getMonth() + ",商户质量报告记录缺少商户质量指导分类");
            }
            merchDepositLoan.setCmmdQtrId(merchReport.getRepQtrId());
            merchDepositLoanDao.saveOrUpd(merchDepositLoan);
        }catch (BaseException e) {
            e.printStackTrace();
            return taskReuslt(JobCommon.Status.FAIL.getValue(),false, e.getMsg());
        }catch (Exception ex){
            ex.printStackTrace();
            String exType = ex.getClass().getSimpleName();
            return taskReuslt(Status.FAIL.getValue(),false,"异常类型：" + exType + ",异常信息：" + ex.getMessage());
        }
        return taskReuslt(JobCommon.Status.SUCCESS.getValue(),false,"ok");
    }

    /**
     * 直绑/全量账户-月日均规模
     * todo 缺少数据来源
     */
    public Long monthAvgAmtSum(List<AccountInfoPO> acctList,String mctNo){
        acctList = acctList.stream().filter(o -> LongUtil.equals(o.getActMctNo(),Long.valueOf(mctNo))).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(acctList)){
            return 0L;
        }
        return acctList.stream().mapToLong(o -> o.getAvgDepositAmount().longValue()).sum();
    }

    /**
     * 直绑/全量账户-月末时点规模
     * todo 缺少数据来源
     */
    public Long monthLastdayAmtSum(List<AccountInfoPO> acctList,String mctNo){
        acctList = acctList.stream().filter(o -> LongUtil.equals(o.getActMctNo(),Long.valueOf(mctNo))).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(acctList)){
            return 0L;
        }
        return acctList.stream().mapToLong(o -> o.getLastDayAmount()==null?0:o.getLastDayAmount().longValue()).sum();
    }

    /**
     * 直绑/全量账户-偏离度
     * 公式：（月末时点规模-月日均规模） / 月日均规模*100%
     */
    public BigDecimal deviationDegree(Long bindMonthAvgAmt,Long bindMonthLastdayAmt){
        if(Objects.isNull(bindMonthAvgAmt) || bindMonthAvgAmt==0){
            throw new BaseException("月日均规模不能为空");
        }
        BigDecimal monthAvgAmt = new BigDecimal(bindMonthAvgAmt);
        BigDecimal lastdayAmt = bindMonthLastdayAmt==null?new BigDecimal(0):new BigDecimal(bindMonthLastdayAmt);

        return lastdayAmt.subtract(monthAvgAmt).divide(monthAvgAmt,2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
    }

    /**
     * 直绑/全量账户-加权存款利率
     * 公式：逐户对直绑/全量账户 存款利率累加/总户数
     * todo 缺少数据来源
     */
    public BigDecimal weightDepositRate(List<AccountInfoPO> acctList,String mctNo){
        acctList = acctList.stream().filter(o -> LongUtil.equals(o.getActMctNo(),Long.valueOf(mctNo))).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(acctList)){
            return new BigDecimal(0);
        }
        List<BigDecimal> rateList = acctList.stream().map(o -> o.getDepositRate()).collect(Collectors.toList());
        BigDecimal total = BigDecimalUtils.add(rateList);
        return total.divide(new BigDecimal(acctList.size()),2,BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 授信规模
     * 公式：对有授信标识的全量账户求和
     * todo 缺少数据来源，暂时不确定此处是用直绑账户还是全量账户
     */
    public BigDecimal creditAmtSum(List<AccountInfoPO> acctList,String mctNo){
        List<BigDecimal> creditAmtlist = acctList.stream()
                .filter(o -> LongUtil.equals(o.getActMctNo(),Long.valueOf(mctNo))
                        && o.getCreditFlag()!=null && o.getCreditFlag().equals(String.valueOf(CreditFlagEnum.授信.getValue())))
                .map(o -> o.getCreditAmt()).collect(Collectors.toList());
        return BigDecimalUtils.add(creditAmtlist);
    }

    /**
     * 用信规模
     * 公式：对有用信标识的全量账户求和
     * todo 缺少数据来源，暂时不确定此处是用直绑账户还是全量账户
     */
    public BigDecimal useCreditAmtSum(List<AccountInfoPO> acctList,String mctNo){
        List<BigDecimal> useCreditAmtlist = acctList.stream()
                .filter(o -> LongUtil.equals(o.getActMctNo(),Long.valueOf(mctNo))
                        && o.getUseCreditFlag()!=null && o.getUseCreditFlag().equals(String.valueOf(UseCreditFlagEnum.用信.getValue()))).map(o -> o.getUseCreditAmt()).collect(Collectors.toList());
        return BigDecimalUtils.add(useCreditAmtlist);
    }

    /**
     * 存贷比
     * 公式：用信规模/直绑账户月日均规模 * 100%
     */
    public BigDecimal ratio(BigDecimal useCreditTotalAmt,Long bindMonthAvgAmt){
        return BigDecimalUtils.mul(BigDecimalUtils.div(useCreditTotalAmt,bindMonthAvgAmt,2),new BigDecimal(100));
    }

}
